package gui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;

import logic.English;
import logic.PlayfairCipher;
import logic.PlayfairKey;
import logic.SolutionListener;
import vis.CipherPanel;
import vis.KeyPanel;
import vis.PrepChecker;
import vis.TextCheckPanel;
import cruncher.TetragraphMap;

public class MainWindow extends JFrame implements ActionListener, SolutionListener {
	private static final long serialVersionUID = -7357382131277128445L;

	private JTabbedPane jtp = null;
	
	JButton btnEnc = null, btnDec = null;
	JTextField tf1, tf2, tf3, tf4;
	PlayfairCipher cipher = new PlayfairCipher(new English());
	KeyPanel kp = new KeyPanel(cipher, true);
	JProgressBar jpb = new JProgressBar(0, 99);
	JButton startDec = new JButton("Start");
	JButton stopDec = new JButton("Stop");
	DefaultListModel lm = new DefaultListModel();
	JList list = new JList(lm);
	JScrollPane jsp = null;
	
	PlayfairKey decKey = new PlayfairKey("a", new English());
	
	public MainWindow()
	{
		super("Playfair - A. Stancic 09/08");
		PlayfairCipher pc = new PlayfairCipher(new English(), "PlayfairExample");
		
		jtp = new JTabbedPane();
		
		JPanel pan1 = new JPanel();
		pan1.setLayout(new BorderLayout());
		TextCheckPanel tcp = new TextCheckPanel(new PrepChecker(pc), "Originalni tekst", "Tekst za šifrovanje");
		tcp.setText("Hide the gold in the tree stump.");
		tcp.setEditable(true);
		pan1.add(tcp, BorderLayout.CENTER);
		JLabel lbl1 = new JLabel("<html><p align=center>" + LangMgr.getString("priprema-label") + "</p></html>");
		pan1.add(lbl1, BorderLayout.SOUTH);
		jtp.addTab("Priprema teksta", pan1);
		
		JPanel pan2 = new JPanel();
		pan2.setLayout(new BorderLayout());
		CipherPanel cp = new CipherPanel(pc, false, true);
		cp.setText("Hide the gold in the tree stump.");
		pan2.add(cp, BorderLayout.CENTER);
		pan2.add(new JLabel("<html><p align=center>" + LangMgr.getString("sifrovanje-label") + "</p></html>"), BorderLayout.SOUTH);
		jtp.addTab("Šifrovanje", pan2);
		
		JPanel pan3 = new JPanel();
		pan3.setLayout(new GridBagLayout());
		GridBagConstraints gbc = null;
		
		gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0;
		pan3.add(new JLabel("Tekst"), gbc);
		gbc = new GridBagConstraints(); gbc.gridx = 1; gbc.gridy = 0; gbc.weightx = 0.8;
		tf1 = new JTextField();
		tf1.setFont(new Font(Font.MONOSPACED, Font.BOLD, 16));
		tf1.setPreferredSize(new Dimension(500, 30));
		pan3.add(tf1, gbc);
		gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 1;
		pan3.add(new JLabel("Ključ"), gbc);
		gbc = new GridBagConstraints(); gbc.gridx = 1; gbc.gridy = 1; gbc.weightx = 0.8;
		tf2 = new JTextField();
		tf2.setFont(new Font(Font.MONOSPACED, Font.BOLD, 16));
		tf2.setPreferredSize(new Dimension(500, 30));
		pan3.add(tf2, gbc);
		gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 3;
		pan3.add(new JLabel("Rezultat"), gbc);
		gbc = new GridBagConstraints(); gbc.gridx = 1; gbc.gridy = 3; gbc.weightx = 0.8;
		tf3 = new JTextField();
		tf3.setFont(new Font(Font.MONOSPACED, Font.BOLD, 16));
		tf3.setPreferredSize(new Dimension(500, 30));
		pan3.add(tf3, gbc);
		JPanel dummy = new JPanel();
		dummy.add(btnEnc = new JButton("Enkriptuj"), gbc);
		dummy.add(btnDec = new JButton("Dekriptuj"), gbc);
		btnEnc.addActionListener(this);
		btnDec.addActionListener(this);
		gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 4; gbc.gridwidth = 2;
		pan3.add(dummy, gbc);
		
		jtp.addTab("Šifrovanje/dešifrovanje", pan3);
		
		JPanel pan4 = new JPanel();
		pan4.setLayout(new BoxLayout(pan4, BoxLayout.Y_AXIS));
		gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; gbc.ipady = 10;
		pan4.add(new JLabel("Šifrat"), gbc);
		gbc = new GridBagConstraints(); gbc.gridx = 1; gbc.gridy = 0; gbc.weightx = 0.8; gbc.ipady = 10;
		tf4 = new JTextField();
		tf4.setFont(new Font(Font.MONOSPACED, Font.BOLD, 16));
		tf4.setPreferredSize(new Dimension(500, 30));
		tf4.setMaximumSize(new Dimension(1000, 30));
		tf4.setText(LangMgr.getString("default-cipher"));
		pan4.add(tf4, gbc);
		
		gbc = new GridBagConstraints(); gbc.gridx = 1; gbc.gridy = 1; gbc.gridwidth = 2; gbc.gridheight = 1; gbc.ipady = 10;
		pan4.add(kp, gbc);
		
		gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 2; gbc.gridwidth = 2; gbc.ipady = 10;
		pan4.add(startDec, gbc);
		startDec.addActionListener(this);
		
		gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 3; gbc.gridwidth = 2;
		pan4.add(jpb, gbc);
		jpb.setPreferredSize(new Dimension(600, 20));
		
		gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 4; gbc.gridwidth = 2; gbc.weightx = 1.0;
		jsp = new JScrollPane(list);

		pan4.add(jsp, gbc);
		
		jtp.addTab("Kriptoanaliza", pan4);
		
		add(jtp);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setPreferredSize(new Dimension(800, 600));
		pack();
		setVisible(true);
	}
	
	public static void main(String[] args) {
		new MainWindow();
	}

	@Override
	public void actionPerformed(ActionEvent arg0) {
		if(arg0.getSource() == btnEnc)
		{
			if(tf1.getText().length() == 0 || tf2.getText().length() == 0)
				return;
			
			PlayfairCipher pfc = new PlayfairCipher(new English(), tf2.getText());
			tf3.setText(pfc.cipherString(tf1.getText()));
		}
		
		if(arg0.getSource() == btnDec)
		{
			if(tf1.getText().length() == 0 || tf2.getText().length() == 0)
				return;
			
			PlayfairCipher pfc = new PlayfairCipher(new English(), tf2.getText());
			tf3.setText(pfc.decipherString(tf1.getText()));
		}
		
		if(arg0.getSource() == startDec)
		{
			if(tf4.getText().length() == 0) return;
			
			decKey = PlayfairKey.generateRandomKey(cipher.getLanguage());
			decKey.setSolutionListener(this);
			TetragraphMap tetra = new TetragraphMap(cipher);
			tetra.loadBinary("tetragraphs.bin");
			PlayfairKey.cipher = cipher;
			PlayfairKey.tetraMap = tetra;
			PlayfairKey.cipherText = tf4.getText();
			lm = new DefaultListModel();
			list.setModel(lm);
			
			Thread t = new Thread(new Runnable() {
				
				@Override
				public void run() {
					startDec.setEnabled(false);
					tf4.setEnabled(false);
					decKey.findSolution(tf4.getText(), 100);
				}
			});
			
			t.start();
		}
	}

	@Override
	public void done() {
		startDec.setEnabled(true);
		tf4.setEditable(true);
	}

	@Override
	public void iteration(int iter) {
		jpb.setValue(iter);
	}

	@Override
	public void solution(String res, PlayfairKey key) {
		lm.add(lm.size(), res);
		list.repaint();

		int lastIndex = list.getModel().getSize() - 1;
		if (lastIndex >= 0) {
			list.ensureIndexIsVisible(lastIndex);
		}

		cipher.setKey(key);
		kp.repaint();
	}

}
